import sys
if __name__ == '__main__':
    sys.path.append('../../')


import requests
import time
import json
from quant.markets import OrderBook, MarketData, Functions
from quant.markets.functions import get_asset_value
from quant.utils import logging, catch_exception, Timer2
from quant.accounts import Order
from quant.exchanges.basics import Socket, ChannelBasic, HandlerBasic, ApiBasic, SpiBasic
from quant.exchanges.util import AscendingChecker, int_prec_to_precision, spot_value_factor, simulate_deal_usdt_swap
from quant.exchanges.binance_util import build_request
from quant.const import *


"""
并入模板，需添加一些bn没有的特性。比如is_welcome_msg: self.info_welcome()
"""


class BinanceSwapUsdtChannel(ChannelBasic):
    def init(self):
        if self.event == Event.Book:
            host = book_host(self.symbol, self.frequency)
        elif self.event == Event.Trade:
            host = trade_host(self.symbol, self.frequency)
        elif self.event == Event.Ticker:
            host = ticker_host(self.symbol, self.frequency)
        else:
            raise NotImplementedError('Event for {} not implemented'.format(self.event))

        self.socket = Socket(host, self.on_open, self.on_message, self.on_close)

    def subscribe_book(self, ws):
        pass

    def subscribe_trade(self, ws):
        pass

    def subscribe_ticker(self, ws):
        pass


class BinanceSwapUsdtHandler(HandlerBasic):
    def init(self):
        self.data_id_checker = AscendingChecker()

    def process_book(self, routing_key, recv_time, raw):
        if raw == NAME_CHANNEL_CLOSE:
            return self.process_close(routing_key, recv_time)

        data = json.loads(raw)
        server_id = data['u']
        server_time = data['E'] / 1000
        self.markets.info_engine.push_process_recv(server_id, server_time, recv_time)

        if not self.data_id_checker.is_new(server_id):
            return

        bids = data['b']
        asks = data['a']

        book = self.book
        for p, v in bids:
            book['buy', float(p)] = float(v)
        for p, v in asks:
            book['sell', float(p)] = float(v)

        self.check_book(book)
        self.push_book(routing_key, recv_time, server_time, server_id, book)

    def process_trade(self, routing_key, recv_time, raw):
        if raw == NAME_CHANNEL_CLOSE:
            return self.process_close(routing_key, recv_time)

        data = json.loads(raw)
        server_id = data['l']
        server_time = data['E'] / 1000
        self.markets.info_engine.push_process_recv(server_id, server_time, recv_time)

        if not self.data_id_checker.is_new(server_id):
            return

        trade_list = [[
            side_map[data['m']],
            float(data['p']),
            float(data['q']),
        ]]

        self.push_trade(routing_key, recv_time, server_time, server_id, trade_list)

    def process_ticker(self, routing_key, recv_time, raw):
        if raw == NAME_CHANNEL_CLOSE:
            return self.process_close(routing_key, recv_time)

        j = json.loads(raw)
        server_id = j['u']
        server_time = j['E'] / 1000
        self.markets.info_engine.push_process_recv(server_id, server_time, recv_time)

        if not self.data_id_checker.is_new(server_id):
            return

        ticker = (
            (float(j['b']), float(j['B'])),
            (float(j['a']), float(j['A'])),
        )
        self.push_ticker(routing_key, recv_time, server_time, server_id, ticker)


class BinanceSwapUsdtApi(ApiBasic):
    def set_ws_mode(self, ws=True):
        return

    def query_margin(self, symbol=None):
        path = 'fapi/v1/account'
        req = build_request(rest_host, 'GET', path, self.api_key, self.secret_key)
        self.requesting.request_async(symbol, req, self._on_margin)

    def query_all_margin(self):
        path = 'fapi/v1/account'
        req = build_request(rest_host, 'GET', path, self.api_key, self.secret_key)
        self.requesting.request_async('all', req, self._on_margin)

    def query_position(self, symbol=None):
        path = 'fapi/v1/positionRisk'
        req = build_request(rest_host, 'GET', path, self.api_key, self.secret_key)
        self.requesting.request_async(symbol, req, self._on_position)

    def query_all_position(self):
        path = 'fapi/v1/positionRisk'
        req = build_request(rest_host, 'GET', path, self.api_key, self.secret_key)
        self.requesting.request_async(None, req, self._on_all_position)

    def query_open_orders(self, symbol=None):
        path = 'fapi/v1/openOrders'
        param = {'symbol': format_symbol(symbol)}
        req = build_request(rest_host, 'GET', path, self.api_key, self.secret_key, param)
        self.requesting.request_async(symbol, req, self._on_open_orders)

    def query_all_open_orders(self):
        path = 'fapi/v1/openOrders'
        req = build_request(rest_host, 'GET', path, self.api_key, self.secret_key)
        self.requesting.request_async(None, req, self._on_all_open_orders)

    def place_order(self, order):
        order = order.copy()
        assert order.client_id is None
        if order.order_type is None:
            order.order_type = OrderType.Limit

        order.operate_now()
        order.status = OrderStatus.Placing
        client_id = self._create_cid()
        order.client_id = client_id

        path = 'fapi/v1/order'
        contract = format_symbol(order.symbol)
        side = order.side.upper()

        if order.order_type == OrderType.Market:
            param = dict(
                symbol=contract,
                side=side,
                type='MARKET',
                quantity=order.amount,
                newClientOrderId=client_id,
            )
        else:
            param = dict(
                symbol=contract,
                side=side,
                type='LIMIT',
                quantity=order.amount,
                price=order.price,
                timeInForce=order_type_map[order.order_type],
                newClientOrderId=client_id,
            )

        if not self._ignore_offset:
            if order.offset == Offset.Close:
                param['reduceOnly'] = True

        req = build_request(rest_host, 'POST', path, self.api_key, self.secret_key, param)
        self.account.order_processor.process_place_operation(order)
        self.requesting.request_async(order, req, self._on_place)
        return order.client_id

    def cancel_order(self, order):
        order = order.copy()
        order.operate_now()
        order.status = OrderStatus.Canceling

        client_id = order.client_id
        if client_id is None:
            client_id = ''
            logging.error('cancel order without cid: {}'.format(order))

        path = 'fapi/v1/order'
        param = {
            'symbol': format_symbol(symbol=order.symbol),
            'origClientOrderId': client_id,
        }

        req = build_request(rest_host, 'DELETE', path, self.api_key, self.secret_key, param)
        self.account.order_processor.process_cancel_operation(order)
        self.requesting.request_async(order, req, self._on_cancel)

    def cancel_all(self):
        raise NotImplementedError('cancel_all() not implemented')

    def _on_margin(self, symbol, response):
        if symbol == 'all':
            interest = ('usdt', 'busd')
        else:
            interest = symbol.split('.')[0].split('/')[1]

        if int(response.status_code) // 100 != 2:
            return self._fail_request('query_margin', symbol, response)

        margin = self.account.margin
        for dic in response.json()['assets']:
            asset = dic['asset'].lower()
            if asset in interest:
                bal = float(dic['marginBalance'])
                margin[asset] = bal
        self._put_data(UserEvent.Margin, margin)

    def _on_position(self, symbol, response):
        if int(response.status_code) // 100 != 2:
            return self._fail_request('query_position', symbol, response)

        if symbol is None:
            interest = self._symbol_added
        else:
            interest = {symbol, }

        position = {}
        for dic in response.json():
            sym = resume_symbol(dic['symbol'])
            if sym in interest:
                long, short = 0, 0
                p = float(dic['positionAmt'])
                if p > 0:
                    long = p
                else:
                    short = -p

                position[sym] = {'long': long, 'short': short, 'position': long-short}

        for sym in interest:
            if sym not in position:
                position[sym] = {'long': 0, 'short': 0, 'position': 0}

        self.account.position.update(position)
        self._put_data(UserEvent.Position, position)

    def _on_all_position(self, param, response):
        if int(response.status_code) // 100 != 2:
            return self._fail_request('query_all_position', None, response)

        position = {}
        for dic in response.json():
            contract = dic['symbol']
            tail = contract[-4:]
            if tail != 'USDT' and tail != 'BUSD':
                continue
            symbol = resume_symbol(dic['symbol'])

            pos = float(dic['positionAmt'])
            if pos == 0:
                continue

            long = 0
            short = 0
            if pos > 0:
                long = pos
            else:
                short = -pos
            position[symbol] = {'symbol': symbol, 'long': long, 'short': short, 'position': long-short}

        self.account.position.clear()
        self.account.position.update(position)

        self._put_data(UserEvent.Position, position)

    def _on_open_orders(self, symbol, response):
        if int(response.status_code) // 100 != 2:
            return self._fail_request('query_open_orders', symbol, response)

        contract = format_symbol(symbol)
        open_orders = []
        for dic in response.json():
            if dic['symbol'] == contract:
                order = Order(
                    symbol=symbol,
                    side=dic['side'].lower(),
                    price=float(dic['price']),
                    amount=abs(float(dic['origQty']) - float(dic['executedQty'])),
                    client_id=dic['clientOrderId'],  # 作为template时要注意，有的交易所不会赋值手动单的cid.
                    order_id=dic['orderId'],
                    offset=offset_map[dic['reduceOnly']],
                    status=OrderStatus.Pending,
                )
                open_orders.append(order)

        self.account.order_processor.process_open_orders(open_orders)
        self._put_data(UserEvent.OpenOrders, self.account.orders)

    def _on_all_open_orders(self, param, response):
        if int(response.status_code) // 100 != 2:
            return self._fail_request('query_all_open_orders', None, response)

        open_orders = []
        for dic in response.json():
            order = Order(
                symbol=resume_symbol(dic['symbol']),
                side=dic['side'].lower(),
                price=float(dic['price']),
                amount=abs(float(dic['origQty']) - float(dic['executedQty'])),
                client_id=dic['clientOrderId'],  # 作为template时要注意，有的交易所不会赋值手动单的cid.
                order_id=dic['orderId'],
                offset=offset_map[dic['reduceOnly']],
                status=OrderStatus.Pending,
            )
            open_orders.append(order)

        if open_orders:
            self.account.order_processor.process_open_orders(open_orders)
            self._put_data(UserEvent.OpenOrders, self.account.orders)

    def _on_place(self, order, response):
        order = order.copy()

        if int(response.status_code) // 100 != 2:
            self._fail_request('place_order', order, response)
            order.status = OrderStatus.PlaceFailed
        else:
            j = response.json()
            order.order_id = j['orderId']
            order.status = OrderStatus.Pending

            if order.order_type == OrderType.Market:
                order.status = OrderStatus.FullyFilled

        order = self.account.order_processor.update_order(order)
        self._put_data(UserEvent.Order, order)

    def _on_cancel(self, order, response):
        order = order.copy()

        if int(response.status_code) // 100 != 2:
            self._fail_request('cancel_order', order, response)

        if int(response.status_code) == -1:
            order.status = OrderStatus.CancelFailed
        else:
            order.status = OrderStatus.Canceled

        order = self.account.order_processor.update_order(order)
        self._put_data(UserEvent.Order, order)

    def get_position_mode(self):
        path = 'fapi/v1/positionSide/dual'
        req = build_request(rest_host, 'GET', path, self.api_key, self.secret_key)
        result = self.requesting.request(req)
        return result.json()

    def set_position_mode(self, dual=False):
        path = 'fapi/v1/positionSide/dual'
        param = {'dualSidePosition': dual}
        req = build_request(rest_host, 'POST', path, self.api_key, self.secret_key, param)
        result = self.requesting.request(req)
        return result.json()

    def set_leverage(self, symbol, leverage):
        path = 'fapi/v1/leverage'
        param = {
            'symbol': format_symbol(symbol),
            'leverage': leverage,
        }
        req = build_request(rest_host, 'POST', path, self.api_key, self.secret_key, param)
        result = self.requesting.request(req)
        if result is None:
            return None
        return result.json()

    def get_user_fee(self, symbol):
        path = 'fapi/v1/commissionRate'
        param = {
            'symbol': format_symbol(symbol),
        }
        req = build_request(rest_host, 'GET', path, self.api_key, self.secret_key, param)
        result = self.requesting.request(req)
        return result.json()


class BinanceSwapUsdtSpi(SpiBasic):
    extend_key_started = False

    def add_symbol(self, symbol):
        self._symbol_added.add(symbol)
        self.connect_once()
        if not self.extend_key_started:
            Timer2(self._extend_listen_key, extend_listen_key_interval).start()
            self.extend_key_started = True

    def _create_socket(self):
        socket = Socket('', self._on_open, self._on_message, self._on_close, self._pre_connect)
        return socket

    def _pre_connect(self, ws):
        listen_key = None
        while listen_key is None:
            try:
                listen_key = get_listen_key(self.api_key, self.secret_key)
            except Exception as err:
                message = 'get_listen_key() error: {}'.format(err)
                self.account.info_engine.put_spi_status_info(message)
            if listen_key is None:
                time.sleep(1)

        host = '{}/ws/{}'.format(ws_host, listen_key)
        self._socket.set_host(host)

    def _on_message(self, ws, message):
        j = json.loads(message)
        e = j['e']
        if e == 'ORDER_TRADE_UPDATE':
            self._handle_order(j)
        elif e == 'ACCOUNT_UPDATE':
            self._handle_position(j)
        elif e == 'listenKeyExpired':
            self._on_listen_key_expire()

    def _on_listen_key_expire(self):
        logging.warn('BinanceSwapSpi listen key expired')
        self.account.info_engine.put_spi_status_info('on_listen_key_expire()')
        self._socket.reconnect()

    def _extend_listen_key(self):
        try:
            result = extend_listen_key(self.api_key, self.secret_key)
            message = 'extend_listen_key: {}'.format(result)
            self.account.info_engine.put_spi_status_info(message)
        except Exception as err:
            message = 'extend_listen_key() error: {}'.format(err)
            self.account.info_engine.put_spi_status_info(message)

    def _handle_position(self, data):
        data = data['a']
        if 'B' in data:
            for dic in data['B']:
                if dic['a'] == 'USDT':
                    usdt = dic['wb']
                    margin = self.account.margin
                    margin['usdt'] = float(usdt)
                    self._put_data(UserEvent.Margin, margin)
                    break

        if 'P' in data:
            position = self.account.position

            for s in self._symbol_added:
                if s in position:
                    position[s] = {'long': 0, 'short': 0, 'position': 0}

            for dic in data['P']:
                if dic['ps'] != 'BOTH':
                    continue

                symbol = resume_symbol(dic['s'])
                if symbol not in self._symbol_added:
                    continue

                long, short = 0, 0
                p = float(dic['pa'])
                if p > 0:
                    long = p
                else:
                    short = -p
                position[symbol] = {'symbol': symbol, 'position': long-short, 'long': long, 'short': short}

            self._put_data(UserEvent.Position, position)

    def _handle_order(self, data):
        data = data['o']
        symbol = resume_symbol(data['s'])
        if symbol not in self._symbol_added:
            return

        order = Order(
            symbol=symbol,
            side=data['S'].lower(),
            price=float(data['p']),
            amount=float(data['q']) - float(data['z']),
            client_id=data['c'],
            order_id=data['i'],
            status=status_map[data['X']]
        )

        order = self.account.order_processor.update_order(order)
        self._put_data(UserEvent.Order, order)

        deal = float(data['l'])
        if deal != 0:
            self._put_deal(order, deal)


class BinanceSwapFunctions(Functions):
    def get_all_ticker(self):
        url = 'https://fapi.binance.com/fapi/v1/ticker/24hr'
        response = self.session.get(url, timeout=3)
        if int(response.status_code) // 100 != 2:
            logging.warn('Binance func-api error: {}'.format(response.text))
            return {}

        j1 = response.json()
        d1 = {d['symbol']: d for d in j1}

        url = 'https://fapi.binance.com/fapi/v1/ticker/bookTicker'
        response = self.session.get(url, timeout=3)
        if int(response.status_code) // 100 != 2:
            return {}

        j2 = response.json()
        d2 = {d['symbol']: d for d in j2}

        dic = {}
        for contract in set(d1) & set(d2):
            tail = contract[-4:].lower()
            if tail != 'usdt' and tail != 'busd':
                continue
            symbol = '{}/{}.swap'.format(contract[:-4], contract[-4:]).lower()

            d1_i = d1[contract]
            d2_i = d2[contract]

            combine = dict(d1_i, **d2_i)
            dic[symbol] = combine

        result = {}
        _usdt = get_asset_value('usdt')
        for symbol, d in dic.items():
            result[symbol] = {
                'price': float(d['lastPrice']),
                'vol': float(d['quoteVolume']) * _usdt,
                'value': float(d['lastPrice']) * _usdt,
                'bid': float(d['bidPrice']),
                'ask': float(d['askPrice']),
            }

        return result

    def get_all_precision(self):
        url = 'https://fapi.binance.com/fapi/v1/exchangeInfo'
        response = self.session.get(url, timeout=5)
        if int(response.status_code) // 100 != 2:
            logging.warn('Binance func-api error: {}'.format(response.text))
            return {}

        j = response.json()

        result = {}
        for dic in j['symbols']:
            contract = dic['symbol']
            tail = contract[-4:].lower()
            if tail != 'usdt' and tail != 'busd':
                continue
            symbol = '{}/{}.swap'.format(contract[:-4], contract[-4:]).lower()

            price_unit = None
            amount_unit = None
            for _filter in dic['filters']:
                if _filter['filterType'] == 'PRICE_FILTER':
                    price_unit = _filter['tickSize']
                if _filter['filterType'] == 'LOT_SIZE':
                    amount_unit = _filter['stepSize']

            unit = (price_unit, amount_unit)
            if None in unit:
                print('None in presicion unit:', symbol, dic)
                continue

            result[symbol] = (price_unit, amount_unit)
        return result

    def get_value_factor(self, symbol):
        return spot_value_factor(symbol)

    def get_all_contract_size(self):
        all_ticker = self.get_all_ticker()
        result = {s: 1 for s in all_ticker}
        return result

    def get_recent_trade(self, symbol):
        url = 'https://fapi.binance.com/fapi/v1/trades'
        param = {
            'symbol': symbol.split('.')[0].replace('/', '').upper(),
            'limit': 1000,
        }
        response = self.session.get(url, timeout=3, params=param)

        if int(response.status_code) // 100 != 2:
            logging.warn('Binance func-api error: {}'.format(response.text))
            return []
        j = response.json()

        result = [
            (
                d['id'],
                'sell' if d['isBuyerMaker'] is True else 'buy',
                float(d['price']),
                float(d['qty']),
                d['time'] / 1000,
            )
            for d in j
        ]
        return result

    def simulate_deal(self, order, deal_amount, mid_price, account):  # 特别注意，其它所，size不是1的，计算会不会错误！
        return simulate_deal_usdt_swap(order, deal_amount, mid_price, account)  # todo 未测试busd


def book_host(symbol, frequency):
    contract = symbol.split('.')[0].replace('/', '')
    if frequency == DataFrequency.High:
        freq = '0ms'
    elif frequency == DataFrequency.Normal:
        freq = '100ms'
    else:
        freq = '500ms'

    result = '{}/ws/{}@depth@{}'.format(ws_host, contract, freq)
    return result


def trade_host(symbol, frequency):
    contract = symbol.split('.')[0].replace('/', '')
    if frequency == DataFrequency.High:
        result = '{}/ws/{}@aggTrade'.format(ws_host, contract)
    elif frequency == DataFrequency.Normal:
        result = '{}/ws/{}@aggTrade'.format(ws_host, contract)
    else:
        result = '{}/ws/{}@aggTrade'.format(ws_host, contract)
    return result


def ticker_host(symbol, frequency):
    contract = symbol.split('.')[0].replace('/', '')
    result = '{}/ws/{}@bookTicker'.format(ws_host, contract)
    return result


def format_symbol(symbol):
    return symbol.split('.')[0].replace('/', '').upper()


def resume_symbol(contract):
    if contract[-4:] == 'USDT':
        syb = '{}/{}.swap'.format(contract[:-4].lower(), 'usdt')
        return syb

    if contract[-4:] == 'BUSD':
        syb = '{}/{}.swap'.format(contract[:-4].lower(), 'busd')
        return syb

    if contract.split('_')[-1].isnumeric():
        return None

    else:
        raise Exception('ApiTool.resume_syb() for {} not Implemented'.format(contract))


def get_listen_key(api_key, secret_key):
    path = 'fapi/v1/listenKey'
    req = build_request(rest_host, 'POST', path, api_key, secret_key)
    result = requests.post(req.url, headers=req.headers, timeout=3)
    return result.json()['listenKey']


def extend_listen_key(api_key, secret_key):
    path = 'fapi/v1/listenKey'
    req = build_request(rest_host, 'PUT', path, api_key, secret_key)
    result = requests.put(req.url, headers=req.headers, timeout=3)
    return result.json()


rest_host = 'https://fapi.binance.com'
ws_host = 'wss://fstream.binance.com'

side_map = {True: 'sell', False: 'buy'}
offset_map = {True: Offset.Close, False: Offset.Open}
order_type_map = {OrderType.PostOnly: 'GTX', OrderType.Limit: 'GTC', 'IOC': 'IOC', 'FOK': 'FOK'}
status_map = {'NEW': OrderStatus.Pending, 'PARTIALLY_FILLED': OrderStatus.PartFilled, 'FILLED': OrderStatus.FullyFilled,
              'CANCELED': OrderStatus.Canceled, 'REJECTED': OrderStatus.PlaceFailed,
              'EXPIRED': OrderStatus.Canceled}
extend_listen_key_interval = 600


"""
1. 三种频率测试
"""


if __name__ == '__main__':
    def try_channel():
        from quant import Markets

        mar = Markets()
        # mar.add_market('Book', 'Binance', 'btc/busd.swap')
        # mar.add_market('Trade', 'Binance', 'btc/busd.swap')
        mar.add_market('Trade', 'Binance', 'sol/busd.swap')
        def on_md(md):
            # print(md.data.book_repr())
            for i in md.data:
                print(*i)
        mar.subscribe_all(on_md)

        while True:
            input(':')

    def try_api():
        import quant
        import keys
        from quant.utils import set_test_mode
        from utils import ee_show

        def print_account_orders(account):
            print('-------account-------')
            for o in account.orders.values():
                print(o)

        set_test_mode()
        factory = quant.exchanges.get_factory('Binance')

        key = keys.get_key('bn_1')
        api = factory.api_cls(key)
        api.add_symbol('btc/usdt.swap')

        api.account.info_engine.show_request_fail()
        ee_show(api.account.routing_engine)
        ee_show(api.account.info_engine)
        ee_show(api.account.order_processor.info_engine)

        def on_user_data(user_data):
            print('on_user_data:', user_data)
        api.account.subscribe(UserEvent.OpenOrders, on_user_data)

        cid = api.place_order(Order('btc/usdt.swap', 'buy', 50000, 100, order_type=OrderType.PostOnly, offset=Offset.Close))
        print_account_orders(api.account)
        input('')
        print_account_orders(api.account)

    def try_spi():
        import quant
        import keys
        from quant.utils import set_test_mode
        from utils import ee_show
        set_test_mode()

        def print_account_orders(account):
            print('-------account-------')
            for o in account.orders.values():
                print(o)

        factory = quant.exchanges.get_factory('Binance')

        key = keys.get_key('bn_1')
        spi = factory.spi_cls(key)
        spi.add_symbol('btc/usdt.swap')

        spi.account.info_engine.show_request_fail()
        ee_show(spi.account.routing_engine)
        ee_show(spi.account.info_engine)
        ee_show(spi.account.order_processor.info_engine)

        def on_user_data(user_data):
            print('on_user_data:', user_data)
            print_account_orders(spi.account)
        ee = spi.account.info_engine
        ee.subscribe(ee.UserData, on_user_data)

        spi.connect()

        print('----------')

        while True:
            input(':')
            print_account_orders(spi.account)

    def try_api_2():
        import keys
        from quant.accounts import Accounts
        kkk = keys.get_key('bn_j1')
        acc = Accounts().create_account('Binance', kkk)
        acc.info_engine.show_user_data()
        acc.info_engine.show_problems()
        api = acc.api

        # api.query_margin('btc/busd.swap')
        # api.query_all_margin()
        # api.query_all_balance()


        # api.place_order(Order('sol/usdt.swap', 'buy', 20, 1))
        # api.place_order(Order('sol/busd.swap', 'buy', 20, 2))

        # api.query_open_orders('sol/usdt.swap')
        # api.query_all_open_orders()

        # api.cancel_order(Order('sol/usdt.swap', client_id='yh1'))
        # api.cancel_order(Order('sol/busd.swap', client_id='qy1'))

        # api.place_order(Order('sol/usdt.swap', 'buy', 20, 1, order_type=OrderType.Market))
        # api.place_order(Order('sol/busd.swap', 'buy', 20, 2, order_type=OrderType.Market))

        # api.query_position('sol/usdt.swap')
        # api.query_position('sol/busd.swap')
        # api.query_all_position()

        acc.api.join()

    def try_api_3():
        import keys

        for i in range(13):
            key = 'bn_rw{}'.format(i+1)
            api = BinanceSwapUsdtApi(keys.get_key(key))
            print(key, api.get_user_fee('btc/usdt.swap'))
            # print(api.set_leverage('bnx/usdt.swap', 3))
            input(':')
            return

    def try_function():
        from quant.utils import set_test_mode
        from quant.markets.functions import set_quick_mode
        set_test_mode()
        set_quick_mode()

        fn = BinanceSwapFunctions()

        # a = fn.get_all_ticker()
        # li = [(s, d) for s, d in a.items()]
        # li.sort(key=lambda x: x[1]['vol'], reverse=True)
        # for i in li:
        #     print(i)

        # a = fn.get_all_precision()
        # for i in a.items():
        #     print(i)

        a = fn.get_recent_trade('cvx/busd.swap')
        for i in a:
            print(i)

    try_api_2()

























